/**
 * 
 */
package RC.structs;

import graph.Graph;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import mdp.id.RDDL2DD;


/**
 * @author NR
 *
 * TODO
 */
public class DTreeNode<D extends RDDL2DD> extends Node{

	protected Set<String> varsT = null;
	protected Set<String> acutSetT = null;
	public D _context;

	/**
	 * @param pAcutSetT
	 * @param pContext
	 */
	public DTreeNode(Set<String> pAcutSetT, D pContext) {
		super();
		this.acutSetT = pAcutSetT;
		this._context = pContext;
	}

	/**
	 * @param pContext
	 */
	public DTreeNode(D pContext, int Pdd) {
		super();
		this._context = pContext;
		this.dd = Pdd;
	}

	public DTreeNode(D context, DTreeNode<D> low, DTreeNode<D> high) {
		super();
		_high = high;
		_low = low;
		_context = _context;
	}

	@Override
	public Set<String> getContext(){
		HashSet<String> ret = new HashSet<String>(varsT);
		ret.retainAll(acutSetT);
		return Collections.unmodifiableSet(ret);
	}
	
	@Override
	public Set<String> getVars(){
		if( varsT != null ) {
			return Collections.unmodifiableSet(varsT);
		}
		
		if( isLeaf() ) {
			makeLeafVars();
		}else {
			varsT = new HashSet<String>(_high.getVars());
			varsT.addAll(_low.getVars());
		}
		return varsT;
	}
	
	/**
	 * 
	 */
	private void makeLeafVars() {
		varsT = new HashSet<String>();
		Set gids = _context._context.getGIDs(dd);
		for( Object o : gids ) {
			String varname = (String)(_context.getActualVarName((Integer)o));
//			if( _context._alactionvars.contains(varname) ) {
				varsT.add(varname);	
//			}
			
		}
	}

	/* (non-Javadoc)
	 * @see RC.structs.Node#getLabel()
	 */
	@Override
	public String getLabel() {
		String ret = "vars : " + varsT.toString() + "\n";
		ret += "acutset : " + acutSetT.toString() + "\n";
		if( !isLeaf() ) {
			ret += "cutset : " + getCutSet().toString() + "\n";
		}
		ret += "context : " + getContext().toString() + "\n";
		return ret;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return getLabel();
	}
	/**
	 * @return
	 */
	public Set<String> getCutSet() {
		
		Set<String> ret = new HashSet<String>(_high.getVars());
		ret.retainAll(_low.getVars());
		ret.removeAll(getAcutSet());
		return Collections.unmodifiableSet(ret);
	}

	/**
	 * @return
	 */
	private Set<String> getAcutSet() {
		return Collections.unmodifiableSet(acutSetT);
	}

	/* (non-Javadoc)
	 * @see RC.structs.Node#seed(int)
	 */
	@Override
	public ArrayList<Integer> seed(Set<String> aCutSet) throws Exception {
		this.acutSetT = new HashSet<String>(aCutSet);

		if(! isLeaf() ){
			Set<String> cutset = getCutSet();
			Set<String> param = new HashSet<String>(cutset);
			param.addAll(aCutSet);
			
			ArrayList<Integer> ret1 = _high.seed(param);
			ArrayList<Integer> ret2 = _low.seed(param);
			
			ArrayList<Integer> ret = new ArrayList<Integer>();
			ret.add(Math.max(Math.max(cutset.size(), ret1.get(0)), ret2.get(0)));
			ret.add(Math.max(Math.max(acutSetT.size(), ret1.get(1)), ret2.get(1)));
			ret.add(Math.max(Math.max(getContext().size(), ret1.get(2)), ret2.get(2)));
			
			return ret;
		}else {
			ArrayList<Integer> ret = new ArrayList<Integer>();
			ret.add(varsT.size());
			ret.add(acutSetT.size());
			ret.add(getContext().size());
			return ret;
		}
		
	}

	@Override
	public void toGraph(Graph g) {
		
		if( isLeaf() ) {
//			String lab = getVars().toString();
//			g.addNodeLabel("#"+id+"#", lab);
		}else {
//			g.addNodeLabel("#"+id+"#", getCutSet() + "\n" + getAcutSet());
//			System.out.println("Connecting " + lab + " " + _high.getLabel());
			g.addUniLink("#"+id+"#", "#"+_high.id+"#");
//			System.out.println("Connecting " + lab + " " + _low.getLabel());
			g.addUniLink("#"+id+"#", "#"+_low.id+"#");
//			g.launchViewer();
			_high.toGraph(g);
			_low.toGraph(g);
		}
		
	}
	
	/* (non-Javadoc)
	 * @see RC.structs.Node#hashCode()
	 */
	@Override
	public int hashCode() {
		return this.id;
	}

}
